home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HPAVC
/
HPAVC CD-ROM.iso
/
3DDEMO.ZIP
/
3D
/
SOURCE
/
BMAPGFX.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-21
|
13KB
|
480 lines
#include "bmapgfx.hpp"
// Copyright (c) 1996 by Kerrigan Burgess, all rights reserved.
BITMAPGFXCLASS::BITMAPGFXCLASS(void) // constructor.
{
Image=NULL;
}
BITMAPGFXCLASS::~BITMAPGFXCLASS(void) // destructor.
{
if (Image != NULL)
delete Image;
}
void BITMAPGFXCLASS::Create( ImageStats *Stats, unsigned char *bitmap )
{
if (Image != NULL)
delete Image;
Image = new unsigned char [ Stats->size ];
if (Image==NULL)
Error("Not enough memory\n");
Image = bitmap;
MidX = Stats->width/2;
MidY = Stats->height/2;
Coords[0].x = 0-MidX;
Coords[0].y = 0-MidY;
Coords[1].x = 0-MidX;
Coords[1].y = (Stats->height)-MidY;
Coords[2].x = (Stats->width)-MidX;
Coords[2].y = (Stats->height)-MidY;
Coords[3].x = (Stats->width)-MidX;
Coords[3].y = 0-MidY;
Coords[0].u = 1;
Coords[0].v = 1;
Coords[1].u = 1;
Coords[1].v = Stats->height-1;
Coords[2].u = Stats->width-1;
Coords[2].v = Stats->height-1;
Coords[3].u = Stats->width-1;
Coords[3].v = 1;
}
void BITMAPGFXCLASS::Scale(unsigned char *Buffer, float percentage)
{
int x0,y0,x2,y2;
x0 = Coords[0].x*percentage + HALF_SCREEN_WIDTH;
y0 = Coords[0].y*percentage + HALF_SCREEN_HEIGHT;
x2 = Coords[2].x*percentage + HALF_SCREEN_WIDTH;
y2 = Coords[2].y*percentage + HALF_SCREEN_HEIGHT;
ScaleBitMap(x0,y0,x2,y2,
Coords[0].u,Coords[0].v,Coords[2].u,Coords[2].v,
Buffer,Image);
}
void BITMAPGFXCLASS::ScaleBitMap(int x0,int y0,int x2,int y2,
int u0,int v0,int u2,int v2,
unsigned char *Buffer,unsigned char *Image)
{
unsigned char *Source,*Dest;
long LeftU,u,v,Du,Dv;
int x,y,vint;
// This is hard coded for 320x200.
Du = ((u2-u0)<<16)/(x2-x0); // point 16 format.
Dv = ((v2-v0)<<16)/(y2-y0);
LeftU = u0<<16;
v = v0<<16;
if (y0 < _MinClipY)
{
v = v + (_MinClipY - y0)*Dv;
y0 = _MinClipY;
}
if (y2 > _MaxClipY)
y2 = _MaxClipY;
if (x0 < _MinClipX)
{
LeftU = LeftU + (_MinClipX - x0)*Du;
x0 = _MinClipX;
}
if (x2 > _MaxClipX)
x2 = _MaxClipX;
Buffer+=x0+(y0<<8)+(y0<<6);
for (y=y0;y<y2;y++)
{
u=LeftU;
vint=v>>16;
Source=Image+(vint<<8)+(vint<<6);
Dest=Buffer;
for (x=x0;x<x2;x++)
{
*Dest++=Source[ u>>16 ];
u+=Du;
}
v+=Dv;
Buffer+=SCREENWIDTH;
}
}
void BITMAPGFXCLASS::Rotate( unsigned char *Buffer, double angle, float scale)
{
float Cos, Sin, CosScale, CosAspectScale, SinAspect;
static double ang=0;
int x0,y0,x1,y1,x2,y2,x3,y3;
int u0,v0,u1,v1,u2,v2,u3,v3;
ang+=angle;
angle = -ang*DEGREES_TO_RADIANS;
Sin = (float)sin ( angle );
Cos = (float)cos ( angle );
x0 = Coords[0].x*Cos - Coords[0].y*Sin;
y0 = Coords[0].x*Sin + Coords[0].y*Cos;
x1 = Coords[1].x*Cos - Coords[1].y*Sin;
y1 = Coords[1].x*Sin + Coords[1].y*Cos;
x2 = Coords[2].x*Cos - Coords[2].y*Sin;
y2 = Coords[2].x*Sin + Coords[2].y*Cos;
x3 = Coords[3].x*Cos - Coords[3].y*Sin;
y3 = Coords[3].x*Sin + Coords[3].y*Cos;
x0=x0*scale+HALF_SCREEN_WIDTH;
y0=y0*scale+HALF_SCREEN_HEIGHT;
x1=x1*scale+HALF_SCREEN_WIDTH;
y1=y1*scale+HALF_SCREEN_HEIGHT;
x2=x2*scale+HALF_SCREEN_WIDTH;
y2=y2*scale+HALF_SCREEN_HEIGHT;
x3=x3*scale+HALF_SCREEN_WIDTH;
y3=y3*scale+HALF_SCREEN_HEIGHT;
u0=Coords[0].u;
v0=Coords[0].v;
u1=Coords[1].u;
v1=Coords[1].v;
u2=Coords[2].u;
v2=Coords[2].v;
u3=Coords[3].u;
v3=Coords[3].v;
RotateBitMap( x0,y0,x1,y1,x2,y2,
u0,v0,u1,v1,u2,v2,
Buffer, Image);
RotateBitMap( x0,y0,x2,y2,x3,y3,
u0,v0,u2,v2,u3,v3,
Buffer, Image);
}
void BITMAPGFXCLASS::RotateBitMap(int x0,int y0,int x1,int y1,int x2,int y2,
int u0,int v0,int u1,int v1,int u2,int v2,
unsigned char *Buffer,unsigned char *Image)
{
long width, height,slope;
long u,v,ScanU,ScanV,LeftU,LeftV,LeftDu,LeftDv;
long LeftX,RightX,LeftDx,RightDx;
long ClipLeftX,ClipRightX;
int vint,x,y,newx,newu,newv,tempx,tempy,tempu,tempv,ydiff;
int oldx2,oldy2,oldu2,oldv2;
int GENERAL;
unsigned char *Start;
if (y1<y0) // switch. They're in the wrong order.
{
tempx=x0; tempy=y0;
x0=x1; y0=y1;
x1=tempx; y1=tempy;
tempu=u0; tempv=v0;
u0=u1; v0=v1;
u1=tempu; v1=tempv;
}
if (y2<y0) // switch. They're in the wrong order.
{
tempx=x0; tempy=y0;
x0=x2; y0=y2;
x2=tempx; y2=tempy;
tempu=u0; tempv=v0;
u0=u2; v0=v2;
u2=tempu; v2=tempv;
}
if (y2<y1) // switch. They're in the wrong order.
{
tempx=x1; tempy=y1;
x1=x2; y1=y2;
x2=tempx; y2=tempy;
tempu=u1; tempv=v1;
u1=u2; v1=v2;
u2=tempu; v2=tempv;
}
GENERAL=FALSE; // reset cases (for Triangle).
Start=Buffer; // save starting point of Buffer.
if (y0==y1)
goto FLAT_TOP;
if (y1==y2)
goto FLAT_BOTTOM;
else
GENERAL=TRUE;
height = 65536/(y2-y0);
slope = (x2-x0)*height;
newx = x0+( (slope*(y1-y0))>>16 );
newu = (((y1-y0)*u2+(y2-y1)*u0)*height)>>16;
newv = (((y1-y0)*v2+(y2-y1)*v0)*height)>>16;
oldx2 = x2; // save values for later.
oldy2 = y2;
oldu2 = u2;
oldv2 = v2;
x2 = newx;
y2 = y1;
u2 = newu;
v2 = newv;
FLAT_BOTTOM:
if (x2<x1)
{
tempx=x2; x2=x1; x1=tempx;
tempu=u2; u2=u1; u1=tempu;
tempv=v2; v2=v1; v1=tempv;
}
height = 65536/(y2-y0); // fixed point 16.
width = 65536/(x2-x1+1);
LeftDx = (x1-x0)*height;
RightDx = (x2-x0)*height;
LeftDu = (u1-u0)*height;
LeftDv = (v1-v0)*height;
LeftX = x0<<16;
RightX = LeftX + 32768; // 32768 is 0.5 fixed point 16
LeftU = u0<<16;
LeftV = v0<<16;
ScanU = (u2-u1)*width; // constant across whole triangle.
ScanV = (v2-v1)*width;
if (y0 < _MinClipY)
{
ydiff = _MinClipY - y0;
LeftX = LeftX+LeftDx*ydiff;
RightX = RightX+RightDx*ydiff;
LeftU = LeftU+LeftDu*ydiff;
LeftV = LeftV+LeftDv*ydiff;
y0 = _MinClipY;
}
if (y2 > _MaxClipY)
y2 = _MaxClipY;
Buffer+=(y0<<8)+(y0<<6);
if (x0>=_MinClipX && x0<=_MaxClipX &&
x1>=_MinClipX && x1<=_MaxClipX &&
x2>=_MinClipX && x2<=_MaxClipX)
{
for (y=y0;y<y2;y++,Buffer+=SCREENWIDTH)
{
u=LeftU;
v=LeftV;
for (x=( LeftX>>16 );x<=( RightX>>16 );x++)
{
vint=v>>16;
Buffer[x]=Image[ (u>>16)+(vint<<8)+(vint<<6) ];
u+=ScanU;
v+=ScanV;
}
LeftX += LeftDx;
RightX += RightDx;
LeftU += LeftDu;
LeftV += LeftDv;
}
}
else
{
for (y=y0;y<y2;y++,Buffer+=SCREENWIDTH)
{
ClipLeftX = LeftX>>16;
ClipRightX = RightX>>16;
u=LeftU;
v=LeftV;
if (ClipLeftX < _MinClipX)
{
if (ClipRightX < _MinClipX)
{
LeftX += LeftDx; // update the intensities and slopes.
RightX += RightDx; // before continuing.
LeftU += LeftDu;
LeftV += LeftDv;
continue;
}
u = LeftU + (_MinClipX - ClipLeftX)*ScanU;
v = LeftV + (_MinClipX - ClipLeftX)*ScanV;
ClipLeftX = _MinClipX; // the clipped amount.
}
if (ClipRightX > _MaxClipX)
{
if (ClipLeftX > _MaxClipX)
{
LeftX += LeftDx; // update the intensities and slopes.
RightX += RightDx; // before continuing.
LeftU += LeftDu;
LeftV += LeftDv;
continue;
}
ClipRightX = _MaxClipX;
}
for (x=ClipLeftX;x<=ClipRightX;x++)
{
vint=v>>16;
Buffer[x]=Image[ (u>>16)+(vint<<8)+(vint<<6) ];
u+=ScanU;
v+=ScanV;
}
LeftX += LeftDx;
RightX += RightDx;
LeftU += LeftDu;
LeftV += LeftDv;
}
}
if (!GENERAL)
return;
x0 = x1; // setup for FLAT_TOP.
y0 = y1;
u0 = u1;
v0 = v1;
x1 = x2;
u1 = u2;
v1 = v2;
x2 = oldx2;
y2 = oldy2;
u2 = oldu2;
v2 = oldv2;
Buffer = Start; // reset Buffer to starting point.
FLAT_TOP:
if (x1<x0)
{
tempx=x1; x1=x0; x0=tempx;
tempu=u1; u1=u0; u0=tempu;
tempv=v1; v1=v0; v0=tempv;
}
height = 65536/(y2-y0); // fixed point 16.
width = 65536/(x1-x0+1);
LeftDx = (x2-x0)*height; // Inverse left and right slope.
RightDx = (x2-x1)*height;
LeftDu = (u2-u0)*height;
LeftDv = (v2-v0)*height;
LeftX = x0<<16;
RightX = (x1<<16)+32768; // 32768 is 0.5 fixed point 16.
LeftU = u0<<16;
LeftV = v0<<16;
ScanU = (u1-u0)*width;
ScanV = (v1-v0)*width;
if (y0 < _MinClipY)
{
ydiff = _MinClipY - y0;
LeftX = LeftX+LeftDx*ydiff;
RightX = RightX+RightDx*ydiff;
LeftU = LeftU+LeftDu*ydiff;
LeftV = LeftV+LeftDv*ydiff;
y0 = _MinClipY;
}
if (y2 > _MaxClipY)
y2 = _MaxClipY;
Buffer+=(y0<<8)+(y0<<6);
if (x0>=_MinClipX && x0<=_MaxClipX &&
x1>=_MinClipX && x1<=_MaxClipX &&
x2>=_MinClipX && x2<=_MaxClipX)
{
for (y=y0;y<y2;y++,Buffer+=SCREENWIDTH)
{
u=LeftU;
v=LeftV;
for (x=( LeftX>>16 );x<=( RightX>>16 );x++)
{
vint=v>>16;
Buffer[x]=Image[ (u>>16)+(vint<<8)+(vint<<6) ];
u+=ScanU;
v+=ScanV;
}
LeftX += LeftDx;
RightX += RightDx;
LeftU += LeftDu;
LeftV += LeftDv;
}
}
else
{
for (y=y0;y<y2;y++,Buffer+=SCREENWIDTH)
{
ClipLeftX = ( LeftX>>16 );
ClipRightX = ( RightX>>16 );
u=LeftU;
v=LeftV;
if (ClipLeftX < _MinClipX)
{
if (ClipRightX < _MinClipX)
{
LeftX += LeftDx; // update the intensities and slopes.
RightX += RightDx; // before continuing.
LeftU += LeftDu;
LeftV += LeftDv;
continue;
}
u = LeftU + (_MinClipX - ClipLeftX)*ScanU;
v = LeftV + (_MinClipX - ClipLeftX)*ScanV;
ClipLeftX = _MinClipX; // the clipped amount.
}
if (ClipRightX > _MaxClipX)
{
if (ClipLeftX > _MaxClipX)
{
LeftX += LeftDx; // update the intensities and slopes.
RightX += RightDx; // before continuing.
LeftU += LeftDu;
LeftV += LeftDv;
continue;
}
ClipRightX = _MaxClipX;
}
for (x=ClipLeftX;x<=ClipRightX;x++)
{
vint=(v>>16);
Buffer[x]=Image[ (u>>16)+(vint<<8)+(vint<<6) ];
u+=ScanU;
v+=ScanV;
}
LeftX += LeftDx;
RightX += RightDx;
LeftU += LeftDu;
LeftV += LeftDv;
}
}
}